/**********************************queue code start**************************************************************/

// #include <cstdio>
// #include <iostream>
// #include "freertos/FreeRTOS.h"
// #include "freertos/task.h"
// #include "esp_system.h"
// #include <vector>
// #include <string>
// #include <cstring>
// #include "freertos/queue.h"

// typedef struct UDPMessage
// {
//     char Source[6];
//     char Destination[6];
//     // int Length;
//     // int Checksum;
//     // std::string Data;
// } UDPMessage;

// void TaskSend1(void *pvParameters)
// {
//     QueueHandle_t QHandle = (QueueHandle_t)pvParameters;
//     BaseType_t xStace;
//     const char i[6] = "Task1";
//     int j = 0;
//     while (1)
//     {
//         UDPMessage Message;
//         sprintf(Message.Source, "%s", i);
//         sprintf(Message.Destination, "%s", std::to_string(++j).c_str());

//         xStace = xQueueSend(QHandle, &Message, 0);
//         if (xStace == pdPASS)
//         {
//             // std::cout << "Send success Date: " << timenow << std::endl;
//             printf("\nSend success Date:  Source: %s Destination: %s\n", Message.Source, Message.Destination);
//         }
//         else
//         {
//             printf("Send done!\n");
//         }
//         // delete Message;
//         vTaskDelay(1000 / portTICK_PERIOD_MS); // 1 second delay
//     }
//     vTaskDelete(nullptr);
// }

// void TaskSend2(void *pvParameters)
// {
//     QueueHandle_t QHandle = (QueueHandle_t)pvParameters;
//     BaseType_t xStace;
//     const char i[6] = "Task2";
//     int j = 0;
//     while (1)
//     {
//         UDPMessage Message;
//         sprintf(Message.Source, "%s", i);
//         sprintf(Message.Destination, "%s", std::to_string(++j).c_str());

//         xStace = xQueueSend(QHandle, &Message, 0);
//         if (xStace == pdPASS)
//         {
//             // std::cout << "Send success Date: " << timenow << std::endl;
//             printf("\nSend success Date:  Source: %s Destination: %s\n", Message.Source, Message.Destination);
//         }
//         else
//         {
//             printf("Send done!\n");
//         }
//         // delete Message;
//         vTaskDelay(2000 / portTICK_PERIOD_MS); // 1 second delay
//     }
//     vTaskDelete(nullptr);
// }

// void TaskReceive(void *pvParameters)
// {
//     QueueSetHandle_t QSetHandle = (QueueSetHandle_t)pvParameters;
//     QueueSetMemberHandle_t QueueData;
//     BaseType_t xStace;
//     while (1)
//     {
//         UDPMessage Message;
//         QueueData = xQueueSelectFromSet(QSetHandle, portMAX_DELAY);

//         xStace = xQueueReceive(QueueData, &Message, portMAX_DELAY);
//         if (xStace == pdPASS)
//         {
//             printf("\nReceive success Date:  Source: %s Destination: %s\n", Message.Source, Message.Destination);
//         }
//         else
//         {
//             printf("Receive done!\n");
//         }
//         // delete Message;
//         // vTaskDelay(2000 / portTICK_PERIOD_MS); // 2 second delay
//     }
//     vTaskDelete(nullptr);
// }

// extern "C" void app_main()
// {
//     // char buffer[1024];
//     QueueHandle_t xQueue1 = xQueueCreate(5, sizeof(UDPMessage));

//     QueueHandle_t xQueue2 = xQueueCreate(5, sizeof(UDPMessage));

//     QueueSetHandle_t QueueSet = xQueueCreateSet(10 * sizeof(UDPMessage));

//     xQueueAddToSet(xQueue1, QueueSet);
//     xQueueAddToSet(xQueue2, QueueSet);

//     if (xQueue1 == nullptr || xQueue2 == nullptr || QueueSet == nullptr)
//     {
//         printf("Queue create failed\n");
//         return;
//     }
//     else
//     {
//         printf("Queue create success\n");
//         xTaskCreate(TaskSend1, "TaskSend1", 1024 * 5, (void *)xQueue1, 1, nullptr);
//         xTaskCreate(TaskSend2, "TaskSend2", 1024 * 5, (void *)xQueue2, 1, nullptr);
//         xTaskCreate(TaskReceive, "TaskReceive", 1024 * 5, (void *)QueueSet, 2, nullptr);
//     }

//     while (1)
//     {
//         printf("it it main\n");
//         // vTaskList((char *)&buffer);
//         // printf("task_name   task_state  priority   stack  tasK_num\n");
//         // printf("%s\n", buffer);
//         vTaskDelay(5000 / portTICK_PERIOD_MS); // 5 second delay
//     }
// }
/*********************************queue code end***************************************************************/

/************************************timer code end**************************************************************/
// #include <cstdio>
// #include <cstring>
// #include "freertos/FreeRTOS.h"
// #include "freertos/task.h"
// #include "freertos/timers.h"

// typedef struct TestData
// {
//     char Source[20];
//     char Destination[20];
// } TestData;

// void TimerCallback(TimerHandle_t xTimer)
// {
//     TestData *pvTimerID = (TestData *)pvTimerGetTimerID(xTimer);
//     const char *timername = pcTimerGetName(xTimer);
//     printf("%s, %s %s\n", timername, pvTimerID->Source, pvTimerID->Destination);
// }

// extern "C" void app_main()
// {
//     TimerHandle_t timer0; // 定义一个定时器句柄
//     TimerHandle_t timer1; // 定义一个定时器句柄
//     TestData testdata = {"Source1", "Destination1"};
//     timer0 = xTimerCreate("timer0", pdMS_TO_TICKS(1000), pdTRUE, (void *)&testdata, TimerCallback); // 创建一个定时器，周期为1秒，自动重载，传入参数为0
//     timer1 = xTimerCreate("timer1", pdMS_TO_TICKS(500), pdTRUE, (void *)&testdata, TimerCallback);  // 创建一个定时器，周期为1秒，自动重载，传入参数为0
//     xTimerStart(timer0, 0);                                                                         // 启动定时器
//     xTimerStart(timer1, 0);                                                                         // 启动定时器
//     xTimerChangePeriod(timer0, 500, 0);                                                             // 修改定时器周期为500ms
//     xTimerReset(timer0, 1500);                                                                      // 重置定时器1500ms后开始
//     while (1)
//     {
//         printf("it it main\n");
//         vTaskDelay(5000 / portTICK_PERIOD_MS); // 5 second delay
//     }
// }
/************************************timer code end*************************************************************/

/************************************udp code begin*************************************************************/

#include "udpServer.hpp"
#include "tcpClient.hpp"
#include "esp_wifi_netif.h"
#include "WiFi.h"
#include <string>
#include <iostream>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "nvs_flash.h"
#include "esp_log.h"
#include "esp_err.h"

using namespace udp_server;
using namespace tcp_client;
using namespace WIFI;

class Main final
{
    
public:
    void run(void)
    {
        wifiState = Wifi.GetState();
        switch (wifiState)
        {
        case WIFI::Wifi::state_e::READY_TO_CONNECT:
            ESP_LOGI("Wifi Status", "READY_TO_CONNECT");
            Wifi.Begin();
            break;
        case WIFI::Wifi::state_e::DISCONNECTED:
            ESP_LOGI("Wifi Status", "DISCONNECTED");
            Wifi.Begin();
            break;
        case WIFI::Wifi::state_e::CONNECTING:
            ESP_LOGI("Wifi Status", "CONNECTING");
            break;
        case WIFI::Wifi::state_e::WAITING_FOR_IP:
            ESP_LOGW("Wifi Status", "WAITING_FOR_IP");
            break;
        case WIFI::Wifi::state_e::ERROR:
            ESP_LOGE("Wifi Status", "ERROR");
            break;
        case WIFI::Wifi::state_e::CONNECTED:
            ESP_LOGI("Wifi Status", "CONNECTED");
            break;
        case WIFI::Wifi::state_e::NOT_INITIALIZED:
            ESP_LOGW("Wifi Status", "NOT_INITIALIZED");
            break;
        case WIFI::Wifi::state_e::INITIALIZED:
            ESP_LOGI("Wifi Status", "INITIALIZED");
            break;
        }
    }

    void setup(void)
    {
        esp_event_loop_create_default();
        nvs_flash_init();

        Wifi.SetCredentials("esp32-s3-wifi", "12345678");
        Wifi.Init();
    }

    WIFI::Wifi::state_e GetWifiState(void)
    {
        return Wifi.GetState();
    }

    WIFI::Wifi::state_e wifiState{WIFI::Wifi::state_e::NOT_INITIALIZED};
    WIFI::Wifi Wifi;
};

Main App;

#define HOST_IP_ADDR "192.168.137.1"
#define PORT 8080

void routeMessage(int sock, uint16_t port, std::string message);

static void udp_server_task(void *pvParameters)
{
    UDPServer *server = new UDPServer(PORT, routeMessage); // 创建一个UDP服务器对象

    while (App.GetWifiState() != WIFI::Wifi::state_e::CONNECTED)
        vTaskDelay(1000 / portTICK_PERIOD_MS);

    server->initServer(); // 初始化服务器
    server->start();      // 启动服务器
}

static void tcp_client_task(void *pvParameters)
{
    tcpClient *client = new tcpClient(HOST_IP_ADDR, PORT);
    while (App.GetWifiState() != WIFI::Wifi::state_e::CONNECTED)
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    client->initClient();
    client->start();
}

extern "C" void app_main(void)
{
    App.setup();
    // xTaskCreate(tcp_client_task, "tcp_client", 4096, NULL, 5, NULL);
    xTaskCreate(udp_server_task, "udp_server_task", 4096, NULL, 5, NULL);
    // xTaskCreate(tcp_client_task, "tcp_client_task", 4096, NULL, 5, NULL);
    while (1)
    {
        char buffer[1024];
        App.run();
        vTaskList(buffer);
        printf("task_name   task_state  priority   stack  tasK_num\n");
        printf("%s", buffer);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

void routeMessage(int sock, uint16_t port, std::string message)
{
    ssize_t s = send(sock, message.c_str(), message.size(), 0); // 发送UDP数据
    if (s < 0)
    {
        ESP_LOGW(udp_server::TAG, "send failed");
    }
    else
    {
        ESP_LOGI(udp_server::TAG, "send success: %s", message.c_str());
    }
}